package org.example.util.sql;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.example.annotation.QueryLikeType;
import org.example.mvc.obj.Entity;
import org.example.util.ReflectUtil;
import org.example.util.collection.MapUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.*;


/**
 * TODO 写个注释呗
 *
 * @author Maple
 * @date 2023-12-06
 */
@Slf4j
public class WrapperUtil {

    public static String toULC (String key) {
        return StrUtil.toUnderlineCase(key).toUpperCase() + "_";
    }

    private static <E> Class<?> getTableClass(Class<E> eClass) {
        if(null == eClass) return null;
        if(eClass.isAnnotationPresent(TableName.class)) return eClass;
        return getTableClass(eClass.getSuperclass());
    }


    public static <E> QueryWrapper<E> getEntryQueryWrapper (E entry) {
        Map<String, ?> map = MapUtil.toMap(entry);
        Map<String, Object> newMap = MapUtil.getMap(map.size());

        QueryWrapper<E> queryWrapper = new QueryWrapper<>();

        queryWrapper.allEq(newMap);

        setQueryColum(queryWrapper, null, map);

        return queryWrapper;
    }


    public static <E> QueryWrapper<E> getMapQueryWrapper (Map<String, ?> map, List<String> selectColum) {
        Map<String, Object> newMap = MapUtil.getMap(map.size());
        map.forEach((k, v) -> newMap.put(toULC(k), v));
        QueryWrapper<E> queryWrapper = new QueryWrapper<>();
        setQueryColum(queryWrapper, null == selectColum ? null : selectColum.toArray(new String[0]), null);
        queryWrapper.allEq(newMap);
        return queryWrapper;
    }

    public static <E> QueryWrapper<E> getLikeQueryWrapper (E entry, List<String> selectColum) {

        Map<String, ?> map = MapUtil.toMap(entry);

        Map<String, QueryLikeType> enableKeys = ReflectUtil.getCanLikeByLikeKeys(getTableClass(entry.getClass()));

        QueryWrapper<E> queryWrapper = new QueryWrapper<>();

        if(enableKeys.isEmpty()) {
            return queryWrapper;
        }

        setQueryColum(queryWrapper, null != selectColum ? selectColum.toArray(new String[0]) : null, enableKeys);

        for(String key : map.keySet()) {
            Object inputVal = map.get(key);
            if(null == inputVal) continue; // 2024年03月14日 null就不应该再去搜索了！！！
            setLikeValue(key, inputVal, enableKeys, queryWrapper);
        }

        return queryWrapper;
    }

    private static <E> void setLikeValue(String key, Object inputVal, Map<String, QueryLikeType> enableKeys, QueryWrapper<E> queryWrapper) {

        if(null == inputVal) return;

        QueryLikeType queryLikeType = enableKeys.get(key);

        if(inputVal instanceof String && ((String) inputVal).isEmpty()) return;

        String underlineKey = toULC(key);

        switch (queryLikeType) {
            case LIKE_RIGHT: queryWrapper.likeRight(underlineKey, inputVal); break;
            case LIKE_LEFT: queryWrapper.likeLeft(underlineKey, inputVal); break;
            case LIKE_HAVE: queryWrapper.like(underlineKey, inputVal); break;
            case EQUALS: queryWrapper.eq(underlineKey, inputVal); break;
            case LT: queryWrapper.lt(underlineKey, inputVal); break;
            case GT: queryWrapper.gt(underlineKey, inputVal); break;
        }

    }

    public static <E> void setQueryColum(QueryWrapper<E> wrapper, String[] queryColum, Map<String, ?> keys) {

        if(null == queryColum || queryColum.length == 0) return;

        Set<String> query = new HashSet<>();

        for (String colum : queryColum) {
            if (StringUtils.isNotEmpty(colum) && (null == keys || keys.containsKey(colum)))
                    query.add(toULC(colum));
        }

        query.add("id");

        wrapper.select(query.toArray(queryColum));

    }

    public static <T> Set<String> getAllColum (Class<T> clazz) {
        try {

            Set<String> columns = new HashSet<>();

            Field[] declaredFields = clazz.getDeclaredFields();
            Field[] fields = clazz.getFields();

            for(Field field : declaredFields) {
                TableField annotation = field.getAnnotation(TableField.class);
                if(null != annotation && ! annotation.exist()) continue;
                columns.add(toULC(field.getName()));
            }

            for(Field field : fields) {
                TableField annotation = field.getAnnotation(TableField.class);
                if (null != annotation && !annotation.exist()) continue;
                columns.add(toULC(field.getName()));
            }

            return columns;
        } catch (Exception e) {
            log.error("获取实体类字段异常 class: {}", clazz.getName(), e);
            return null;
        }

    }


    public static <E extends Entity> QueryWrapper<E> getInQueryWrapper(String colum, List<?> value) {
        QueryWrapper<E> queryWrapper = new QueryWrapper<>();
        queryWrapper.in(colum, value);
        return queryWrapper;
    }
}
